package cryptodb

import (
	"bytes"
	"crypto/aes"
	"crypto/cipher"
	"encoding/hex"
	"errors"
	"reflect"
)

var aes256key = "MvTXiGm56*XOT@0%hc5f+oLs!NTaStdv"
var iv = []byte("vz=b)$x11%E#dRsE")

// 加密函数：
func encrypt(plaintext []byte, key []byte) (string, error) {
	// 创建 AES 分组密码对象
	block, err := aes.NewCipher(key)
	if err != nil {
		return "", err
	}

	// 对数据进行填充
	if len(plaintext)%aes.BlockSize != 0 {
		paddingLen := aes.BlockSize - len(plaintext)%aes.BlockSize
		padding := bytes.Repeat([]byte{byte(paddingLen)}, paddingLen)
		plaintext = append(plaintext, padding...)
	}

	// 对数据进行加密
	ciphertext := make([]byte, aes.BlockSize+len(plaintext))
	copy(ciphertext[:aes.BlockSize], iv)
	mode := cipher.NewCBCEncrypter(block, iv)
	mode.CryptBlocks(ciphertext[aes.BlockSize:], plaintext)

	// 将加密后的数据转换为十六进制字符串并返回
	return hex.EncodeToString(ciphertext), nil
}

// 解密函数：
func decrypt(ciphertext string, key []byte) ([]byte, error) {
	// 将加密后的数据从十六进制字符串转换回字节数组
	data, err := hex.DecodeString(ciphertext)
	if err != nil {
		return nil, err
	}

	// 检查数据长度是否正确
	if len(data) < aes.BlockSize {
		return nil, errors.New("ciphertext too short")
	}

	// 提取 IV 和密文
	iv := data[:aes.BlockSize]
	ciphertext = string(data[aes.BlockSize:])

	// 创建 AES 分组密码对象
	block, err := aes.NewCipher(key)
	if err != nil {
		return nil, err
	}

	// 对数据进行解密
	mode := cipher.NewCBCDecrypter(block, iv)
	decrypted := make([]byte, len(ciphertext))
	mode.CryptBlocks(decrypted, []byte(ciphertext))

	// 去掉填充部分并返回解密后的数据
	padLen := int(decrypted[len(decrypted)-1])
	return decrypted[:len(decrypted)-padLen], nil
}

func Encrypt[T interface{}](value T) interface{} {
	v := reflect.ValueOf(value)
	if !v.IsValid() {
		return nil
	}

	switch v.Kind() {
	case reflect.String:
		r, err := encrypt([]byte(v.String()), []byte(aes256key))
		if err != nil {
			return v.String()
		}
		return string(r)
	case reflect.Int, reflect.Int32, reflect.Int64:
		return reflect.ValueOf(v.Int() ^ int64(aes256key[0])).Convert(v.Type()).Interface()
	case reflect.Uint, reflect.Uint32, reflect.Uint64:
		return reflect.ValueOf(v.Uint() ^ uint64(aes256key[0])).Convert(v.Type()).Interface()
	default:
		return value
	}
}

func Decrypt[T interface{}](value T) interface{} {
	v := reflect.ValueOf(value)
	if !v.IsValid() {
		return nil
	}

	switch v.Kind() {
	case reflect.String:
		r, err := decrypt(v.String(), []byte(aes256key))
		if err != nil {
			return v.String()
		}
		return string(r)
	case reflect.Int, reflect.Int32, reflect.Int64:
		return reflect.ValueOf(v.Int() ^ int64(aes256key[0])).Convert(v.Type()).Interface()
	case reflect.Uint, reflect.Uint32, reflect.Uint64:
		return reflect.ValueOf(v.Uint() ^ uint64(aes256key[0])).Convert(v.Type()).Interface()
	default:
		return value
	}
}

func Init(key string) {
	aes256key = key
}
